#include "qemu/osdep.h"
#include "hw/boards.h"
#include "hw/arm/boot.h"
#include "hw/loader.h"
#include "qapi/error.h"


struct BoardState {
    /*< private >*/
    MachineState parent;
    /*< public >*/
	ARMCPU *cpu[1];
	MemoryRegion iram;
    MemoryRegion dram;
};

/* 此处定义的宏的名字是局部的，字符串需要全局唯一 */
#define TYPE_BOARD MACHINE_TYPE_NAME("x210bv3s")
OBJECT_DECLARE_SIMPLE_TYPE(BoardState, BOARD)

static struct arm_boot_info boot_info = {
	/* 该值需要比-kernel指定的可执行文件要大，此处0x18000(96KB)是iRAM的大小，
	   运行裸机程序时，-kernel后面应当指定elf文件 */
	.ram_size = 0x18000,
};

static void board_init(MachineState *ms)
{
	MachineClass *mc = MACHINE_GET_CLASS(ms);
	BoardState *s = BOARD(ms);
	MemoryRegion *system_mem = get_system_memory();

	/* Create cpu */
	Object *cpuobj = object_new(mc->default_cpu_type);
	qdev_realize(DEVICE(cpuobj), NULL, &error_fatal);
	s->cpu[0] = ARM_CPU(cpuobj);

	/* Create iRAM */
	/* iRAM: 0xD0020000-0xD0038000:96KB */
    memory_region_init_ram(&s->iram, NULL, "iram",
	                       0xD0038000-0xD0020000, &error_fatal);
    memory_region_add_subregion(system_mem, 0xD0020000, &s->iram);

	/* 启动-kernel的加载，若不执行该函数，qemu仍可以连接gdb，但不会加载-kernel
	   指定的固件 */
	arm_load_kernel(s->cpu[0], ms, &boot_info);
}

static void board_class_init(ObjectClass *oc, void *data)
{
	MachineClass *mc = MACHINE_CLASS(oc);
    static const char * const valid_cpu_types[] = {
        ARM_CPU_TYPE_NAME("cortex-a8"),
        NULL
    };

    mc->desc = "X210BV3S S5PV210 (Cortex-A8)";
    mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a8");
    mc->valid_cpu_types = valid_cpu_types;
    mc->init = board_init;
	/* 定义该值为true，程序访问非法内存时不会产生内存访问异常 */
    mc->ignore_memory_transaction_failures = false;
}

static const TypeInfo board_info = {
    .name = TYPE_BOARD,
    .parent = TYPE_MACHINE,
    .instance_size = sizeof(BoardState),
    .class_init = board_class_init,
};

static void machine_register(void)
{
    type_register_static(&board_info);
}

type_init(machine_register)
